1. SpringBoot

空~2022年9月6日
  • SpringBoot
大约 14 分钟

1. SpringBoot

介绍

SpringBoot 是 Spring 中的一个成员, 可以简化 Spring, SpringMVC 的使用. 他的核心还是 IOC 容器.

特点:

  • Create stand-alone Spring applications

    创建 spring 应用

  • Embed Tomcat, Jetty or Undertow directly (no need to deploy WAR files)

    内嵌的 tomcat, jetty , Undertow

  • Provide opinionated 'starter' dependencies to simplify your build configuration

    提供了 starter 起步依赖, 简化应用的配置.

    比如使用 MyBatis 框架 , 需要在 Spring 项目中, 配置 MyBatis 的对象 SqlSessionFactory , Dao 的代理对象

    在 SpringBoot 项目中, 在 pom.xml 里面, 加入一个 mybatis-spring-boot-starter 依赖

  • Automatically configure Spring and 3rd party libraries whenever possible

    尽可能去配置 spring 和第三方库.叫做自动配置(就是把 spring 中的, 第三方库中的对象都创建好, 放到容器中, 开发人员可以直接使用)

  • Provide production-ready features such as metrics, health checks, and externalized configuration

    提供了健康检查, 统计, 外部化配置

  • Absolutely no code generation and no requirement for XML configuration

    不用生成代码, 不用使用 xml, 做配置

创建 Spring Boot 项目

使用 maven 创建

创建一个 maven 空项目

image-20220921164157688

参考 SpringBoot 官网[Getting Started (spring.io)open in new window创建 SpringBoot 项目

导入 SpringBoot 父工程 pom 配置

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>myproject</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.7.3</version>
    </parent>

    <!-- Additional lines to be added here... -->

</project>

添加 web 依赖

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>

编写 "Hello World!"

@RestController
@SpringBootApplication
public class MyApplication {

    @RequestMapping("/")
    String home() {
        return "Hello World!";
    }

    public static void main(String[] args) {
        SpringApplication.run(MyApplication.class, args);
    }
}

运行 main 方法后直接在浏览器访问 http://localhost:8080/open in new window 即可, SpringBoot 已经集成 tomcat.

运行时可以查看控制台打印的日志信息:

image-20220921170832567

使用模板创建

使用 Spring 提供的初始化器, 就是向导创建 SpringBoot 应用

默认地址: https://start.spring.ioopen in new window

国内的地址: https://start.SpringBoot.ioopen in new window

image-20220913232532302

image-20220913232703854

image-20220913232924041

SpringBoot 项目的结构:

image-20210115152427829

自动装配原理

依赖管理

SpringBoot 使用父项目做依赖管理

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.3</version>
</parent>

我们的项目在继承了父项目后就无需关注其他依赖的版本号, 原因是 spring-boot-starter-parent 的父项目 spring-boot-dependencies 里面声明了几乎所有常用依赖

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-dependencies</artifactId>
    <version>2.7.3</version>
</parent>

image-20220921172549716

当需要使用自己的版本依赖时可以和往常一样添加<version>标签或者重写 SpringBoot 默认的版本号

<properties>
    <mysql.version>5.1.43</mysql.version>
</properties>

开发导入 starter 场景启动器

  1. 见到很多 spring-boot-starter-*: *就某种场景
  2. 只要引入 starter,这个场景的所有常规需要的依赖我们都自动引入
  3. SpringBoot 所有支持的场景 Developing with Spring Bootopen in new window
  4. 见到的 *-spring-boot-starter: 第三方为我们提供的简化开发的场景启动器
  5. 所有场景启动器最底层的依赖

自动装配

点开 spring-boot-starter-web 查看

  • 自动配好 Tomcat
  • 引入 Tomcat 依赖

  • 配置 Tomct

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-tomcat</artifactId>
  <version>2.7.3</version>
  <scope>compile</scope>
</dependency>
  • 自动配好 SpringMVC
  • 引入 SpringMVC 全套组件

  • 自动配好 SpringMVC 常用组件(功能)

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-web</artifactId>
  <version>5.3.22</version>
  <scope>compile</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-webmvc</artifactId>
  <version>5.3.22</version>
  <scope>compile</scope>
</dependency>
  • 自动配好 Web 常见功能,如:字符编码问题
  • SpringBoot 帮我们配置好了所有 web 开发的常见场景

main 中调用的 run 方法能够返回 ioc 容器, 可以查看全部的 SpringBoot 组件

@RestController
@SpringBootApplication
public class MyApplication {
    public static void main(String[] args) {
        // 返回IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(MyApplication.class, args);
        // 查看容器内的组件
        for (String name : run.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
}

组件包含几乎所有常见配置

如前端控制器 dispatcherServlet

image-20220921180215243

统一字符编码 characterEncodingFilter

image-20220921180501525

视图解析器 viewResolver

image-20220921180657382

文件上传解析器 multipartResolver

image-20220921180811087

  • 默认的包结构
  • 主程序所在包及其下面的所有子包里面的组件都会被默认扫描进来

  • 无需以前的包扫描配置

  • 想要改变扫描路径: @SpringBootApplication(scanBasePackages = "com.example")

@SpringBootConfiguration 包含了 @ComponentScan

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
    @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {}

所以主配置类也可以写成

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan("com.example")
public class MyApplication {}
  • 各种配置拥有默认值
  • 默认配置最终都是映射到某个类上, 如: MultipartProperties
  • 配置文件的值最终会绑定每个类上, 这个类会在容器中创建对象
  • 按需加载所有自动配置项
  • 非常多的 starter
  • 引入了哪些场景这个场景的自动配置才会开启
  • SpringBoot 所有的自动配置功能都在 spring-boot-autoconfigure 包里面

注解的使用

@SpringBootApplication

主方法中的 @SpringBootApplication 是一个复合注解:

  • @SpringBootConfiguration

  • @EnableAutoConfiguration

  • @ComponentScan

@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
        @Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class)})
public @interface SpringBootApplication {
}

@SpringBootConfiguration

该注解依旧是一个复合注解:

@Configuration
@Indexed
public @interface SpringBootConfiguration {
    @AliasFor(
        annotation = Configuration.class
    )
    boolean proxyBeanMethods() default true;
}

@Configuration

public @interface Configuration {
    @AliasFor(annotation = Component.class)
    String value() default "";
    boolean proxyBeanMethods() default true;
}

因为包含了 @Configuration 注解 所以使用了 @SpringBootConfiguration 注解标注的类, 也可以作为配置文件使用的, 可以使用 Bean 声明对象, 注入到容器.

@EnableAutoConfiguration

@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {
    String ENABLED_OVERRIDE_PROPERTY = "spring.boot.enableautoconfiguration";
    Class<?>[] exclude() default {};
    String[] excludeName() default {};
}

启用自动配置, 把 java 对象配置好, 注入到 spring 容器中. 例如可以把 mybatis 的对象创建好, 放入到容器中

@AutoConfigurationPackage

@Import(AutoConfigurationPackages.Registrar.class)
public @interface AutoConfigurationPackage {
  String[] basePackages() default {};
  Class<?>[] basePackageClasses() default {};
}

AutoConfigurationPackages.Registrar.class 类是自动装配的核心

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
        register(registry, new PackageImports(metadata).getPackageNames().toArray(new String[0]));
    }
    @Override
    public Set<Object> determineImports(AnnotationMetadata metadata) {
        return Collections.singleton(new PackageImports(metadata));
    }
}

AnnotationMetadata metadata: 注解元信息, 即 @AutoConfigurationPackage, 又因为 @SpringBootApplication 包含了 @AutoConfigurationPackage, 所以 metadata 获取到的元数据就是主程序类

image-20220921211236311

new PackageImports(metadata).getPackageNames(): 通过元数据获取到该类的所在的包

image-20220921211529068

最后通过包名将该包下所有的组件都注册到容器内

@Import(AutoConfigurationImportSelector.class)

在源码内利用 getAutoConfigurationEntry(annotationMetadata); 方法给容器批量导入一些组件

最终利用 List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes); 获取所有需要导入到容器的组件

SpringBoot 2.7.3 版本有 144 个组件

image-20220921212814239

getCandidateConfigurations(annotationMetadata, attributes) 方法最终利用工厂Map<String, List<String>> loadSpringFactories(ClassLoader classLoader)加载所有方法

getCandidateConfigurations--> loadFactoryNames--> loadSpringFactories

@ComponentScan

public @interface ComponentScan {
    @AliasFor("basePackages")
    String[] value() default {};
    @AliasFor("value")
    String[] basePackages() default {};
    Class<?>[] basePackageClasses() default {};
    Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
    Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
    ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
    String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
    boolean useDefaultFilters() default true;
    Filter[] includeFilters() default {};
    Filter[] excludeFilters() default {};
    boolean lazyInit() default false;
    @Retention(RetentionPolicy.RUNTIME)
    @Target({})
    @interface Filter {
        FilterType type() default FilterType.ANNOTATION;
        @AliasFor("classes")
        Class<?>[] value() default {};
        @AliasFor("value")
        Class<?>[] classes() default {};
        String[] pattern() default {};
    }
}

@ComponentScan 包扫描器, 找到注解, 根据注解的功能创建对象, 给属性赋值等等. 默认扫描的包: @ComponentScan 所在的类所在的包和子包(SpringBoot 主配置类在项目主目录的原因).

SpringBoot 的配置文件

配置文件名称: application

扩展名有: properties( k=v); yml(yaml) ( k: v)

使用 application.properties, application.yml

具体都可以配置哪些信息参考官方文档

Common Application Properties (spring.io)open in new window

properties

提示

properties 优先级最高

例 1: application.properties 设置 端口和上下文

#设置端口号
server.port=8082
#设置访问应用上下文路径, contextpath
server.servlet.context-path=/myboot

yml(yaml)

例 2: application.yml

server:
  port: 8083
  servlet:
    context-path: /myboot2

相关信息

YAML 是 "YAML Ain't Markup Language"(YAML 不是一种标记语言)的递归缩写。

在开发的这种语言时,YAML 的意思其实是:"Yet Another Markup Language"(仍是一种标记语言)。

非常适合用来做以数据为中心的配置文件

基本语法

  • key: value;kv 之间有空格
  • 大小写敏感
  • 使用缩进表示层级关系
  • 缩进不允许使用 tab,只允许空格
  • 缩进的空格数不重要,只要相同层级的元素左对齐即可
  • '#'表示注释
  • 字符串无需加引号,如果要加,''与""表示字符串内容 会被 转义/不转义

数据类型

  • 字面量:单个的、不可再分的值。date、boolean、string、number、null

    k: v
    
  • 对象:键值对的集合。map、hash、set、object

    # 行内写法:
    k: {k1:v1,k2:v2,k3:v3}
    # 或
    k:
      k1: v1
      k2: v2
      k3: v3
    
  • 数组:一组按次序排列的值。array、list、queue

    # 行内写法:
    k: [v1,v2,v3]
    #或者
    k:
     - v1
     - v2
     - v3
    

示例

@Data
public class Person {

  private String userName;
  private Boolean boss;
  private Date birth;
  private Integer age;
  private Pet pet;
  private String[] interests;
  private List<String> animal;
  private Map<String, Object> score;
  private Set<Double> salarys;
  private Map<String, List<Pet>> allPets;
}
@Data
public class Pet {
  private String name;
  private Double weight;
}
# yaml表示以上对象
person:
  userName: zhangsan
  boss: false
  birth: 2019/12/12 20:12:33
  age: 18
  pet:
    name: tomcat
    weight: 23.4
  interests: [篮球, 游泳]
  animal:
    - jerry
    - mario
  score:
    english:
      first: 30
      second: 40
      third: 50
    math: [131, 140, 148]
    chinese: { first: 128, second: 136 }
  salarys: [3999, 4999.98, 5999.99]
  allPets:
    sick:
      - { name: tom }
      - { name: jerry, weight: 47 }
    health: [{ name: mario, weight: 47 }]

配置提示

自定义的类和配置文件绑定一般没有提示

<!-- 配置提示 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

<!-- 项目打包时忽略该jar包 -->
<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <configuration>
                <excludes>
                    <exclude>
                        <groupId>org.springframework.boot</groupId>
                        <artifactId>spring-boot-configuration-processor</artifactId>
                    </exclude>
                </excludes>
            </configuration>
        </plugin>
    </plugins>
</build>

多环境配置

有开发环境, 测试环境, 上线的环境.

每个环境有不同的配置信息, 例如端口, 上下文件, 数据库 url, 用户名, 密码等等

使用多环境配置文件, 可以方便的切换不同的配置.

使用方式: 创建多个配置文件, 名称规则: application-环境名称.properties(yml)

创建开发环境的配置文件: application-dev.properties(application-dev.yml)

创建测试者使用的配置: application-test.properties

  • 创建不同环境下的配置文件

image-20220916173533051

  • 在 properties 配置文件下指定当前使用的配置文件

    指定对应文件后缀就行

# 激活使用哪个配置文件
spring.profiles.active=dev

@Value

从配置文件中获取数据

@Value("$(key)"), key 来自 application.properties(yml)

  • 编写配置文件

    #配置端口号
    server.port=8082
    #context-path
    server.servlet.context-path=/myboot
    
  • 在 Controller 层使用@Value 注解获取配置文件的信息

    @Controller
    public class HelloController {
    
        @Value("${server.port}")
        private Integer port;
    
        @Value("${server.servlet.context-path}")
        private String contextPath;
    
        @RequestMapping("/hello")
        @ResponseBody
        public String queryData() {
            return "port:" + port + " contextPath:" + contextPath;
        }
    }
    
  • 启动项目并根据配置文件的配置信息进行访问

    image-20220916175427502

@ConfigurationProperties

@ConfigurationProperties: 把配置文件的数据映射为 java 对象.

只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能, 一般需要配合 @Component 一起使用

属性: prefix 配置文件中的某些 key 的开头的内容.

@Data
@Component
@ConfigurationProperties(prefix = "school")
public class SchoolInfo {

    private String name;

    private String website;

    private String address;
}

application.properties

#配置端口号
server.port=8082
#context-path
server.servlet.context-path=/myboot

#自定义key=value
school.name=动力节点
school.website=www.bjpowernode.com
school.address=北京的大兴区

controller

@Controller
public class HelloController {

    @Resource
    SchoolInfo schoolInfo;

    @RequestMapping("/hello")
    @ResponseBody
    public String queryData() {
        return schoolInfo.toString();
    }
}

image-20220916180739437

如果出现乱码检查一下配置文件的编码格式

image-20220916180835005

image-20220916180923093

使用 jsp

提示

SpringBoot 不推荐使用 jsp , 而是使用模板技术代替 jsp

使用 jsp 需要配置:

  1. 加入一个处理 jsp 的依赖. 负责编译 jsp 文件

    <dependency>
        <groupId>org.apache.tomcat.embed</groupId>
        <artifactId>tomcat-embed-jasper</artifactId>
    </dependency>
    
  2. 如果需要使用 servlet, jsp, jstl 的功能

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>jstl</artifactId>
    </dependency>
    
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
    </dependency>
    
    <dependency>
    <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>2.3.1</version>
    </dependency>
    
  3. 创建一个存放 jsp 的目录, 一般叫做 webapp

    image-20220917130113087

    将目录修改为 web 资源目录

    image-20220917130216502

    image-20220917130310800

    image-20220917132523344

    <%@ page contentType="text/html;charset=UTF-8" language="java" %>
    <html>
    <head>
        <title>Title</title>
    </head>
    <body>
    ${jsp}
    </body>
    </html>
    
  4. 需要在 pom.xml 指定 jsp 文件编译后的存放目录

    <build>
        <!--指定jsp编译后的存放目录-->
        <resources>
            <resource>
                <!--jsp原来的目录-->
                <directory>src/main/webapp</directory>
                <!--指定编译后的目录-->
                <targetPath>META-INF/resources</targetPath>
                <!--指定处理的目录和文件-->
                <includes>
                    <include>**/*.*</include>
                </includes>
            </resource>
        </resources>
    </build>
    
  5. 创建 Controller, 访问 jsp

    @RequestMapping("/getJsp")
    public String getJsp(Model model) {
        // request.setAttribute("jsp", "getJsp");
        model.addAttribute("jsp", "getJsp");
        // 视图逻辑名称
        return "index";
    }
    
  6. 在 application.propertis 文件中配置视图解析器

    #配置视图解析器
    #/ = src/main/webapp
    spring.mvc.view.prefix=/
    spring.mvc.view.suffix=.jsp
    

正确编译后 target 目录结构:

image-20220917132648653

使用容器

通过代码, 从容器中获取对象.

通过 SpringApplication.run(Application.class, args); 返回值获取容器.

主配置类的 run() 方法源码:

public static ConfigurableApplicationContext run(Class<?> primarySource, String... args) {
        return run(new Class[]{primarySource}, args);
}

返回的数据类型 ConfigurableApplicationContext 的源码:

public interface ConfigurableApplicationContext extends ApplicationContext, Lifecycle, Closeable {
  String CONFIG_LOCATION_DELIMITERS = ",; \t\n";
  String CONVERSION_SERVICE_BEAN_NAME = "conversionService";
  String LOAD_TIME_WEAVER_BEAN_NAME = "loadTimeWeaver";
  String ENVIRONMENT_BEAN_NAME = "environment";
  String SYSTEM_PROPERTIES_BEAN_NAME = "systemProperties";
  String SYSTEM_ENVIRONMENT_BEAN_NAME = "systemEnvironment";
  String APPLICATION_STARTUP_BEAN_NAME = "applicationStartup";
  String SHUTDOWN_HOOK_THREAD_NAME = "SpringContextShutdownHook";
  void setId(String id);
  void setParent(@Nullable ApplicationContext parent);
  void setEnvironment(ConfigurableEnvironment environment);
  @Override
  ConfigurableEnvironment getEnvironment();
  void setApplicationStartup(ApplicationStartup applicationStartup);
  ApplicationStartup getApplicationStartup();
  void addBeanFactoryPostProcessor(BeanFactoryPostProcessor postProcessor);
  void addApplicationListener(ApplicationListener<?> listener);
  void setClassLoader(ClassLoader classLoader);
  void addProtocolResolver(ProtocolResolver resolver);
  void refresh() throws BeansException, IllegalStateException;
  void registerShutdownHook();
  @Override
  void close();
  boolean isActive();
  ConfigurableListableBeanFactory getBeanFactory() throws IllegalStateException;
}

ConfigurableApplicationContext 接口是 ApplicationContext 的子接口

public interface ConfigurableApplicationContext extends ApplicationContext {}
  • 使用 ConfigurableApplicationContextApplicationContext 接收 run() 方法返回的容器对象

  • 使用 getBeanDefinitionNames() 方法可以获取容器内所有的对象名称, 其中就可以找到我们自己创建的对象名称

  • 使用 getBean() 方法获取对象

@SpringBootApplication
public class SpringbootApplication {

    public static void main(String[] args) {
        ApplicationContext context = SpringApplication.run(SpringbootApplication.class, args);
        for (String name : context.getBeanDefinitionNames()) {
          System.out.println(name);
        }
        SchoolInfo schoolInfo = context.getBean("schoolInfo", SchoolInfo.class);
        System.out.println(schoolInfo);
    }
}

CommandLineRunner 接口 , ApplicationRunner 接口

在开发中可能需要在容器启动后执行一些内容, 比如读取配置文件, 数据库连接之类的, SpringBoot 就提供了两个接口来实现该需求.

这两个接口都有一个 run() 方法, 执行时间在容器对象创建好后, 自动执行 run() 方法.

可以完成自定义的在容器对象创建好的一些操作.

CommandLineRunner 接口 run() 方法参数为 String

@FunctionalInterface
public interface CommandLineRunner {
    void run(String... args) throws Exception;
}

ApplicationRunner 接口 run() 方法参数为 ApplicationArguments

@FunctionalInterface
public interface ApplicationRunner {
    void run(ApplicationArguments args) throws Exception;
}

在主配置文件下测试

@SpringBootApplication
public class SpringbootApplication implements CommandLineRunner {

  public static void main(String[] args) {
    System.out.println("准备创建容器对象--run方法执行之前");
    SpringApplication.run(SpringbootApplication.class, args);
    System.out.println("容器对象创建之后--run方法执行之后");
  }

  @Override
  public void run(String... args) throws Exception {
    System.out.println("容器对象创建好之后, 自动执行run方法");
  }
}

控制台打印结果

准备创建容器对象--run方法执行之前

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.7.3)

一些日志信息 ...

容器对象创建好之后, 自动执行run方法
容器对象创建之后--run方法执行之后

结果可以看到:

SpringApplication.run(SpringbootApplication.class, args); 执行时就调用了 CommandLineRunner.run(String... args)

可以在 CommandLineRunner.run(String... args) 方法中调用容器中的对象

  • 为 Student 类 加上 @Component 注解 将该类实例交给 spring 管理

    @AllArgsConstructor
    @NoArgsConstructor
    @Data
    @Component
    public class Student {
        private String name;
        private int age;
        private String sex;
    }
    
  • 在主配置类中使用自动注入获取 Student 对象并尝试在 CommandLineRunner.run(String... args) 方法中调用

    @SpringBootApplication
    public class SpringbootApplication implements CommandLineRunner {
    
      @Resource
      private Student student;
    
        public static void main(String[] args) {
        System.out.println("准备创建容器对象--run方法执行之前");
            SpringApplication.run(SpringbootApplication.class, args);
        System.out.println("容器对象创建之后--run方法执行之后");
      }
    
      @Override
      public void run(String... args) throws Exception {
        student.setName("小明");
        System.out.println("CommandLineRunner.run()中调用容器对象:" + student);
        System.out.println("容器对象创建好之后, 自动执行run方法");
      }
    }
    
  • 可以成功调用

    准备创建容器对象--run方法执行之前
    
      .   ____          _            __ _ _
     /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
    ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
     \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
      '  |____| .__|_| |_|_| |_\__, | / / / /
     =========|_|==============|___/=/_/_/_/
     :: Spring Boot ::                (v2.7.3)
    
    一些日志信息 ...
    
    CommandLineRunner.run()中调用容器对象:Student(name=小明, age=0, sex=null)
    容器对象创建好之后, 自动执行run方法
    容器对象创建之后--run方法执行之后